﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Xml;
using System.Windows.Forms;
using System.IO;

namespace SpriteEditor
{
    class XmlEngine
    {
        // Types of modules
        public static int TYPE_IMAGE = 0;
        public static int TYPE_RECT = 1;
        public static int TYPE_FILL_RECT = 2;

        public static String[] module_types = {"IMAGE", "RECT", "FILL_RECT"};

        public static String getTypeOfModule_String(int m_type)
        {
            if (m_type < 0 || m_type >= module_types.Count())
                return null;
            return module_types[m_type];
        }

        public static int getTypeOfModule_Int(String s_type)
        {
            if (s_type == null)
                return 0;

            s_type.Trim();
            for (int i = 0; i < module_types.Count(); i++)
            {
                if (s_type.Equals(module_types[i]))
                    return i;
            }
            return 0;
        }

        //Flags of modules
        public static int FLAG_FLIP_X = 1;
        public static int FLAG_FLIP_Y = 2;

        public static String[] frame_flags = { "", "FILP_X", "FLIP_Y", "FLIP_X | FLIP_Y" };

        public static String getFlagOfFrame_String(int m_flag)
        {
            m_flag &= 0x00000003;
            return frame_flags[m_flag];
        }

        public static int getFlagOfFrame_Int(String s_flag)
        {
            s_flag.Trim();
            for (int i = 0; i < frame_flags.Count(); i++)
            {
                if (s_flag.Equals(frame_flags[i]))
                    return i;
            }
            return -1;
        }

        // Import and Export
        public static int Export(Sprite spr)
        {
            if (spr == null || spr.sprite_FileName == null || spr.sprite_FileName == "")
                return 0;

            XDocument doc = new XDocument();

            doc.Add(new XComment("Saved by SpriteEditor v0.0.1"));

            XElement root = new XElement("Sprite");
            root.SetAttributeValue("Version", "0.0.1");

            root.Add(new XElement("Num_of_modules", spr.lst_Modules != null ? spr.lst_Modules.Count : 0));
            root.Add(new XElement("Num_of_frames", spr.lst_Frames != null ? spr.lst_Frames.Count : 0));
            root.Add(new XElement("Num_of_animations", spr.lst_Animations != null ? spr.lst_Animations.Count : 0));

            root.Add(new XComment("-----------------"));
            
            	if (spr.spr_image_FileName == null)
            		spr.spr_image_FileName = "";
            		
            if (spr.spr_image_FileName != null)
            {
                XElement e = new XElement("Image");
                e.SetAttributeValue("Path", spr.spr_image_FileName);
                root.Add(e);
            }

            root.Add(new XComment("-----------------"));
            root.Add(new XComment("Type 0 : IMAGE"));
            root.Add(new XComment("Type 1 : RECT"));
            root.Add(new XComment("Type 2 : FILL_RECT"));
            root.Add(new XComment("-----------------"));
            if (spr.lst_Modules != null)
            {
                XElement r_modules = new XElement("Modules");
                foreach (Module md in spr.lst_Modules)
                {
                    XElement e = new XElement("Module");
                    e.SetAttributeValue("Index", md.Index);
                    e.SetAttributeValue("ID", md.ID);
                    e.SetAttributeValue("Type", getTypeOfModule_Int(md.Module_Type));
                    //e.SetAttributeValue("Color", Convert.ToInt32(md.Module_Color, 16));
                    e.SetAttributeValue("Color", md.Module_Color);
                    e.SetAttributeValue("X", md.X);
                    e.SetAttributeValue("Y", md.Y);
                    e.SetAttributeValue("W", md.W);
                    e.SetAttributeValue("H", md.H);
                    e.SetAttributeValue("Desc", md.Desc);
                    r_modules.Add(e);
                }
                root.Add(r_modules);
            }

            root.Add(new XComment("-----------------"));
            root.Add(new XComment("Flags : FLIP_X | FILP_Y"));
            root.Add(new XComment("-----------------"));
            if (spr.lst_Frames != null)
            {
                XElement r_frames = new XElement("Frames");
                foreach (Frame fr in spr.lst_Frames)
                {
                    XElement e = new XElement("Frame");
                    e.SetAttributeValue("Index", fr.Index);
                    e.SetAttributeValue("ID", fr.ID);
                    e.SetAttributeValue("NumOfModules", fr.NumOfModules);
                    e.SetAttributeValue("Desc", fr.Desc);

                    if (fr.lst_ModulesOfFrame != null)
                    {
                        //XElement r_moframe = new XElement("Frame_Modules");
                        foreach (ModulesOfFrame mof in fr.lst_ModulesOfFrame)
                        {
                            XElement e1 = new XElement("FModule");
                            e1.SetAttributeValue("Index", mof.Index);
                            e1.SetAttributeValue("Module_ID", mof.ID);
                            e1.SetAttributeValue("OX", mof.OX);
                            e1.SetAttributeValue("OY", mof.OY);
                            e1.SetAttributeValue("Flags", getFlagOfFrame_Int(mof.Frame_Flags));

                            //r_moframe.Add(e1);
                            e.Add(e1);
                        }
                        //e.Add(r_moframe);
                    }
                    r_frames.Add(e);
                }
                root.Add(r_frames);
            }

            root.Add(new XComment("-----------------"));
            if (spr.lst_Animations != null)
            {
                XElement r_animations = new XElement("Animations");
                foreach (Animation anm in spr.lst_Animations)
                {
                    XElement e = new XElement("Animation");
                    e.SetAttributeValue("Index", anm.Index);
                    e.SetAttributeValue("ID", anm.ID);
                    e.SetAttributeValue("NumOfFrames", anm.NumOfFrames);
                    e.SetAttributeValue("Desc", anm.Desc);

                    if (anm.lst_FramesOfAnimation != null)
                    {
                        //XElement r_moframe = new XElement("Frame_Modules");
                        foreach (FramesOfAnimation foanm in anm.lst_FramesOfAnimation)
                        {
                            XElement e1 = new XElement("AFrame");
                            e1.SetAttributeValue("Index", foanm.Index);
                            e1.SetAttributeValue("Frame_ID", foanm.ID);
                            e1.SetAttributeValue("OX", foanm.OX);
                            e1.SetAttributeValue("OY", foanm.OY);
                            e1.SetAttributeValue("Time", foanm.Time);

                            //r_moframe.Add(e1);
                            e.Add(e1);
                        }
                        //e.Add(r_moframe);
                    }
                    r_animations.Add(e);
                }
                root.Add(r_animations);
            }

            doc.Add(root);
            doc.Save(spr.sprite_FileName);

            string[] lines = File.ReadAllLines(spr.sprite_FileName);
            File.WriteAllLines(spr.sprite_FileName, lines);

            return 1;
        }

        public static int Import(Sprite spr)
        {
            if (spr == null || spr.sprite_FileName == null || spr.sprite_FileName == "")
                return 0;

            try
            {
                XDocument doc = XDocument.Load(spr.sprite_FileName);

                XElement root = doc.Element("Sprite");

                int no_modules = 0;
                int no_frames = 0;
                int no_animations = 0;

                try
                {
                    no_modules = Convert.ToInt32(root.Element("Num_of_modules").Value);
                    no_frames = Convert.ToInt32(root.Element("Num_of_frames").Value);
                    no_animations = Convert.ToInt32(root.Element("Num_of_animations").Value);
                }
                catch (OverflowException)
                {
                    MessageBox.Show("Value is outside the range of the Int32 type.");
                }
                catch (FormatException)
                {
                    MessageBox.Show("The value is not in a recognizable format.");
                }

                spr.spr_image_FileName = root.Element("Image").Attribute("Path").Value;

                if (no_modules > 0)
                {
                    spr.lst_Modules = new List<Module>();

                    XElement r_modules = root.Element("Modules");

                    foreach (XElement e in r_modules.Elements())
                    {
                        spr.lst_Modules.Add(new Module()
                        {
                            Index = Convert.ToInt32(e.Attribute("Index").Value),
                            ID = Convert.ToInt32(e.Attribute("ID").Value),
                            Module_Type = getTypeOfModule_String(Convert.ToInt32(e.Attribute("Type").Value)),
                            //Module_Color = Convert.ToInt32(e.Attribute("Color").Value).ToString("X8"),
                            Module_Color = e.Attribute("Color").Value,
                            X = Convert.ToInt32(e.Attribute("X").Value),
                            Y = Convert.ToInt32(e.Attribute("Y").Value),
                            W = Convert.ToInt32(e.Attribute("W").Value),
                            H = Convert.ToInt32(e.Attribute("H").Value),
                            Desc = e.Attribute("Desc").Value
                        });
                    }
                }

                if (no_frames > 0)
                {
                    spr.lst_Frames = new List<Frame>();

                    XElement r_frames = root.Element("Frames");

                    foreach (XElement e in r_frames.Elements())
                    {
                        Frame tmp_frame = new Frame()
                        {
                            Index = Convert.ToInt32(e.Attribute("Index").Value),
                            ID = Convert.ToInt32(e.Attribute("ID").Value),
                            NumOfModules = Convert.ToInt32(e.Attribute("NumOfModules").Value),
                            Desc = e.Attribute("Desc").Value,
                            lst_ModulesOfFrame = new List<ModulesOfFrame>()
                        };

                        foreach (XElement e1 in e.Elements())
                        {
                            tmp_frame.lst_ModulesOfFrame.Add(new ModulesOfFrame()
                            {
                                Index = Convert.ToInt32(e1.Attribute("Index").Value),
                                ID = Convert.ToInt32(e1.Attribute("Module_ID").Value),
                                OX = Convert.ToInt32(e1.Attribute("OX").Value),
                                OY = Convert.ToInt32(e1.Attribute("OY").Value),
                                Frame_Flags = getFlagOfFrame_String(Convert.ToInt32(e1.Attribute("Flags").Value))
                            });
                        }

                        spr.lst_Frames.Add(tmp_frame);
                    }
                }

                if (no_animations > 0)
                {
                    spr.lst_Animations = new List<Animation>();

                    XElement r_animations = root.Element("Animations");

                    foreach (XElement e in r_animations.Elements())
                    {
                        Animation tmp_animation = new Animation()
                        {
                            Index = Convert.ToInt32(e.Attribute("Index").Value),
                            ID = Convert.ToInt32(e.Attribute("ID").Value),
                            NumOfFrames = Convert.ToInt32(e.Attribute("NumOfFrames").Value),
                            Desc = e.Attribute("Desc").Value,
                            lst_FramesOfAnimation = new List<FramesOfAnimation>()
                        };

                        foreach (XElement e1 in e.Elements())
                        {
                            tmp_animation.lst_FramesOfAnimation.Add(new FramesOfAnimation()
                            {
                                Index = Convert.ToInt32(e1.Attribute("Index").Value),
                                ID = Convert.ToInt32(e1.Attribute("Frame_ID").Value),
                                OX = Convert.ToInt32(e1.Attribute("OX").Value),
                                OY = Convert.ToInt32(e1.Attribute("OY").Value),
                                Time = Convert.ToInt32(e1.Attribute("Time").Value),
                            });
                        }

                        spr.lst_Animations.Add(tmp_animation);
                    }
                }

                return 1;
            }
            catch (System.Xml.XmlException)
            {
                MessageBox.Show("Incorrect format of sprite !!!");
                return 0;
            }
        }
    }
}
